package Metadatos;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.sql.Statement;

import Conexion.Conexion;

public class Metadatos {

	// Devuelve lista de nombres de tablas
	public static LinkedList <String> getNombresTablas(Connection conexion, String catalogo, String esquema) {
		String[] tipo = {"TABLE"};
		DatabaseMetaData metaDatos;
		ResultSet tablas = null;
		LinkedList <String> nombres = new LinkedList <String> ();
		try {
			metaDatos = conexion.getMetaData();
			tablas = metaDatos.getTables(catalogo,esquema, null, tipo);
			while (tablas.next()) {
				nombres.add(tablas.getString(3));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return nombres;
	}
	
	// Devuelve una lista de ternas:  nombre / tipo / longitud / clavePrimaria
	public static LinkedList <String[]>getDatosColumnas(Connection conexion, String tabla, String catalogo, String esquema) {
		DatabaseMetaData metaDatos;
		ResultSet columnas = null; 
		LinkedList <String[]> nombres = new LinkedList <String[]> ();
		LinkedList <String> clavesPrimarias = getClavesPrimarias(conexion, tabla, catalogo, esquema);
		LinkedList <String> indicesUnicos = getIndices(conexion, tabla, catalogo, esquema, true);
		LinkedList <String> indices = getIndices(conexion, tabla, catalogo, esquema, false);
		try {
			metaDatos = conexion.getMetaData();
			columnas = metaDatos.getColumns(catalogo,esquema,tabla,null);
			while (columnas.next()) {
				String [] datosColumna = new String[5];
				datosColumna[0] = columnas.getString(4); //nombre
				datosColumna[1] = columnas.getString(6); //tipo
				datosColumna[2] = columnas.getString(16); //longitud
				if (indices.contains(columnas.getString(4))){
					datosColumna[3] = "INDEX";
					if(indicesUnicos.contains(columnas.getString(4))){
						datosColumna[3] = "UNIQUE";
						if (clavesPrimarias.contains(columnas.getString(4))){
							datosColumna[3] = "PRIMARY KEY";
						}
					}
				}else{
					datosColumna[3] = "";
				}
				nombres.add(datosColumna);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return nombres;
	}
	
	// Devuelve lista de claves primarias
	public static LinkedList <String> getClavesPrimarias(Connection conexion, String tabla, String catalogo, String esquema) {
		DatabaseMetaData metaDatos;
		ResultSet datosClaves = null;
		LinkedList <String> claves = new LinkedList <String> ();
		try {
			metaDatos = conexion.getMetaData();
			datosClaves = metaDatos.getPrimaryKeys(catalogo, esquema, tabla);
			while (datosClaves.next()) {
				claves.add(datosClaves.getString(4));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return claves;
	}
	
	// Devuelve lista de las claves foraneas
	public static LinkedList <String[]> getClavesForaneas(Connection conexion, String tabla, String catalogo, String esquema) {
		DatabaseMetaData metaDatos;
		LinkedList <String[]> claves = new LinkedList <String[]> ();
		LinkedList <String> nombresTablas = getNombresTablas(conexion, catalogo, esquema);
		try {
			metaDatos = conexion.getMetaData();
			for (int i=0;i<nombresTablas.size();i++) {
				ResultSet datosClaves = metaDatos.getImportedKeys(catalogo, esquema, nombresTablas.get(i));
				while (datosClaves.next()) {
					String[] info = new String[7];
					info[0] = datosClaves.getString(12);//fk name
					info[1] = datosClaves.getString(3);//tabla que referencia
					info[2] = datosClaves.getString(4);//columna que referencia
					info[3] = datosClaves.getString(8);//columna referenciada
					info[4] = datosClaves.getString(10);//accion en update
					info[5] = datosClaves.getString(11);//accion en delete
					info[6] = datosClaves.getString(7);//nombre tabla local
					claves.add(info);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return claves;
	}
	
	//Si el parametro "unico" es TRUE devuelve los indices UNIQUE, sino todos.
	public static LinkedList <String> getIndices(Connection conexion, String tabla, String catalogo, String esquema, boolean unico) {
		DatabaseMetaData metaDatos;
		ResultSet datosIndices = null;
		LinkedList <String> indices = new LinkedList <String> ();
		try {
			metaDatos = conexion.getMetaData();
			datosIndices = metaDatos.getIndexInfo(catalogo, esquema, tabla, unico, unico);
			while (datosIndices.next()) {
				indices.add(datosIndices.getString(9));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return indices;
	}
	
	// Retorna una lista de pares  [nombre_trigger , cond_disparo]
	public static LinkedList<String[]> nombresYCondTriggers (Connection conexion,String schema) {
		LinkedList <String[]> triggers = new LinkedList <String[]> ();
		Statement statement = null;
		try {
			statement = conexion.createStatement();
			String query = "Select * from information_schema.triggers where trigger_schema ='"+schema+"'";
			ResultSet resultSet = statement.executeQuery(query);
			while(resultSet.next())
			{
				String [] nombreYCond = new String[4];
				nombreYCond[0] = resultSet.getString(3);//nombreTrigger
				nombreYCond[1] = resultSet.getString(4);//accion(insert,update)
				nombreYCond[2] = resultSet.getString(7);//En que tabla lo hace
				nombreYCond[3] = resultSet.getString(12);//Condicion before after
				triggers.add(nombreYCond);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return triggers;
	}
	
	// Retorna una lista de listas, estas ultimas se componen de [nombre,argumentos,tipos_argumentos]
	@SuppressWarnings("unchecked")
	public static LinkedList getNombresProcedimientos (Connection conexion,String schema) {
		LinkedList resultado = new LinkedList ();
		try {
			DatabaseMetaData metaDato;
			metaDato = conexion.getMetaData();
			
			/*statement = conexion.createStatement();
			String query = "Select proname,proallargtypes,proargnames from pg_proc";*/
			ResultSet resultSet = metaDato.getProcedures(null, schema, null);//usar getProcedureColumns en 
			while(resultSet.next())
			{
				resultado.add(resultSet.getString(3));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return resultado;
	}
	//retorna [nombre, tipo(in, out, etc), tipo, longitud]
	public static LinkedList<String[]> getParametrosProcedimiento(Connection conexion, String schema, String procedimiento){
		LinkedList<String[]> resultado = new LinkedList<String[]>();
		String[] array;
		try {
			DatabaseMetaData metaDato;
			metaDato = conexion.getMetaData();
			ResultSet resultset = metaDato.getProcedureColumns(null, schema, procedimiento, null);
			while(resultset.next()){
				array = new String[3];
				array[0] = resultset.getString(4);
				array[1] = resultset.getString(5);
				array[2] = resultset.getString(7);
				resultado.add(array);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return resultado;
	}
	 	
	public static LinkedList <String> getPalabras (String cadena) {
		LinkedList <String> palabras = new LinkedList <String> ();
		int ultimaComa;
		if (cadena != null) {
			int desde=1, hasta=cadena.indexOf(',');
			ultimaComa = hasta;
			while (hasta != -1) {
				String palabra = cadena.substring(desde, hasta);
				palabras.add(palabra);
				desde = hasta+1;
				hasta = cadena.indexOf(',',hasta+1);
				if (hasta != -1) {
					ultimaComa = hasta;
				}
			}
			String palabra = cadena.substring(ultimaComa+1, cadena.indexOf('}'));
			palabras.add(palabra);
		}
		return palabras;
	}
}









